/*
 * Copyright (c) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "imx458_cmos.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/mman.h>
#include <memory.h>

#ifdef HI_GPIO_I2C
#include "gpioi2c_ex.h"
#else
#include "hi_i2c.h"
#endif

static int g_fd[ISP_MAX_PIPE_NUM] = {[0 ... (ISP_MAX_PIPE_NUM - 1)] = -1};
static HI_BOOL g_bStandby[ISP_MAX_PIPE_NUM] = {0};

#ifndef NA
#define NA 0xFFFF
#endif
#define I2C_DEV_FILE_NUM     16
#define I2C_BUF_NUM          8
int imx458_i2c_init(VI_PIPE vi_pipe)
{
    int ret;
    HI_U8 u8DevNum;
    char acDevFile[I2C_DEV_FILE_NUM];

    if (g_fd[vi_pipe] >= 0) {
        return HI_SUCCESS;
    }
    ISP_SNS_COMMBUS_U *imx458businfo = HI_NULL;

    imx458businfo = imx458_get_bus_Info(vi_pipe);
    u8DevNum = imx458businfo->s8I2cDev;
    ret = snprintf_s(acDevFile, sizeof(acDevFile), sizeof(acDevFile) - 1, "/dev/i2c-%u", u8DevNum);
    if (ret < 0) {
        return HI_FAILURE;
    }

    g_fd[vi_pipe] = open(acDevFile, O_RDWR, S_IRUSR | S_IWUSR);
    if (g_fd[vi_pipe] < 0) {
        SNS_ERR_TRACE("Open /dev/hi_i2c_drv-%u error!\n", u8DevNum);
        return HI_FAILURE;
    }

    ret = ioctl(g_fd[vi_pipe], I2C_SLAVE_FORCE, (IMX458_I2C_ADDR >> 1));
    if (ret < 0) {
        SNS_ERR_TRACE("I2C_SLAVE_FORCE error!\n");
        close(g_fd[vi_pipe]);
        g_fd[vi_pipe] = -1;
        return ret;
    }

    return HI_SUCCESS;
}

int imx458_i2c_exit(VI_PIPE vi_pipe)
{
    if (g_fd[vi_pipe] >= 0) {
        close(g_fd[vi_pipe]);
        g_fd[vi_pipe] = -1;
        return HI_SUCCESS;
    }

    return HI_FAILURE;
}

int imx458_read_register(VI_PIPE vi_pipe, HI_U32 addr)
{
    hi_unused(vi_pipe);
    hi_unused(addr);

    return HI_SUCCESS;
}
int imx458_write_register(VI_PIPE vi_pipe, HI_U32 addr, HI_U32 data)
{
    HI_U32 idx = 0;
    HI_S32 ret;
    HI_U8 buf[I2C_BUF_NUM];

    if (g_fd[vi_pipe] < 0) {
        return HI_SUCCESS;
    }

    if (IMX458_ADDR_BYTE == 2) {  /* 2 byte */
        buf[idx] = (addr >> 8) & 0xff;  /* shift 8 */
        idx++;
        buf[idx] = addr & 0xff;
        idx++;
    } else {
        buf[idx] = addr & 0xff;
        idx++;
    }

    if (IMX458_DATA_BYTE == 2) {  /* 2 byte */
        buf[idx] = (data >> 8) & 0xff;  /* shift 8 */
        idx++;
        buf[idx] = data & 0xff;
        idx++;
    } else {
        buf[idx] = data & 0xff;
        idx++;
    }

    ret = write(g_fd[vi_pipe], buf, (IMX458_ADDR_BYTE + IMX458_DATA_BYTE));
    if (ret < 0) {
        SNS_ERR_TRACE("I2C_WRITE DATA error!\n");
        return HI_FAILURE;
    }

    return HI_SUCCESS;
}

void imx458_standby(VI_PIPE vi_pipe)
{
    HI_S32 ret;
    ret = imx458_write_register(vi_pipe, 0x100, 0x00);
    if (ret != HI_SUCCESS) {
        SNS_ERR_TRACE("write register failed!\n");
        return;
    }
    g_bStandby[vi_pipe] = HI_TRUE;
    return;
}

void imx458_restart(VI_PIPE vi_pipe)
{
    HI_S32 ret;
    ret = imx458_write_register(vi_pipe, 0x100, 0x01);
    if (ret != HI_SUCCESS) {
        SNS_ERR_TRACE("write register failed!\n");
        return;
    }
    g_bStandby[vi_pipe] = HI_FALSE;
    return;
}

void imx458_mirror_flip(VI_PIPE vi_pipe, ISP_SNS_MIRRORFLIP_TYPE_E eSnsMirrorFlip)
{
    switch (eSnsMirrorFlip) {
        default:
        case ISP_SNS_NORMAL:
            imx458_write_register(vi_pipe, 0x101, 0x0);
            break;

        case ISP_SNS_MIRROR:
            imx458_write_register(vi_pipe, 0x101, 0x01);
            break;

        case ISP_SNS_FLIP:
            imx458_write_register(vi_pipe, 0x101, 0x02);
            break;

        case ISP_SNS_MIRROR_FLIP:
            imx458_write_register(vi_pipe, 0x101, 0x03);
            break;
    }

    return;
}

#define IMX458_SENSOR_CFG_SEQ_COMM_COL   2
static const HI_U16 g_au16SensorCfgSeqComm[][IMX458_SENSOR_CFG_SEQ_COMM_COL] = {
    {0x18, 0x0136},
    {0x00, 0x3051},
    {0x00, 0x3052},
    {0x14, 0x4E21},
    {0xCF, 0x6B11},
    {0x08, 0x7FF0},
    {0x1B, 0x7FF3},
    {0x23, 0x7FF4},
    {0x01, 0x7FF7},
    {0x00, 0x7FFD},
    {0xFE, 0x7F77},
    {0xFE, 0x7FA9},
    {0x81, 0x7B24},
    {0x07, 0x6564},
    {0x41, 0x6B0D},
    {0x04, 0x653D},
    {0x8C, 0x6B05},
    {0xF9, 0x6B06},
    {0x65, 0x6B08},
    {0xFC, 0x6B09},
    {0xCF, 0x6B0A},
    {0xD2, 0x6B0B},
    {0x0E, 0x6700},
    {0x0E, 0x6707},
    {0xED, 0x5F05},
    {0x74, 0x94D0},
    {0x74, 0x94D1},
    {0x74, 0x94D2},
    {0x74, 0x95D0},
    {0x74, 0x95D1},
    {0x74, 0x95D2},
    {0x2E, 0x94CD},
    {0x2E, 0x94CE},
    {0x2E, 0x94CF},
    {0x2E, 0x95CD},
    {0x2E, 0x95CE},
    {0x2E, 0x95CF},
    {0x4C, 0x94CA},
    {0x4C, 0x94CB},
    {0x4C, 0x94CC},
    {0x4C, 0x95CA},
    {0x4C, 0x95CB},
    {0x4C, 0x95CC},
    {0x32, 0x900E},
    {0xFF, 0x94E2},
    {0xFF, 0x94E3},
    {0xFF, 0x94E4},
    {0xFF, 0x95E2},
    {0xFF, 0x95E3},
    {0xFF, 0x95E4},
    {0x6E, 0x94DF},
    {0x6E, 0x94E0},
    {0x6E, 0x94E1},
    {0x6E, 0x95DF},
    {0x6E, 0x95E0},
    {0x6E, 0x95E1},
    {0x01, 0x7FCC},
    {0x00, 0x7B78},
    {0x35, 0x9401},
    {0x23, 0x9403},
    {0x23, 0x9405},
    {0x00, 0x9406},
    {0x31, 0x9407},
    {0x00, 0x9408},
    {0x1B, 0x9409},
    {0x00, 0x940A},
    {0x15, 0x940B},
    {0x3F, 0x940D},
    {0x3F, 0x940F},
    {0x3F, 0x9411},
    {0x64, 0x9413},
    {0x64, 0x9415},
    {0x64, 0x9417},
    {0x34, 0x941D},
    {0x01, 0x941F},
    {0x01, 0x9421},
    {0x01, 0x9423},
    {0x23, 0x9425},
    {0x23, 0x9427},
    {0x23, 0x9429},
    {0x2F, 0x942B},
    {0x1A, 0x942D},
    {0x14, 0x942F},
    {0x3F, 0x9431},
    {0x3F, 0x9433},
    {0x3F, 0x9435},
    {0x6B, 0x9437},
    {0x7C, 0x9439},
    {0x81, 0x943B},
    {0x0F, 0x9443},
    {0x0F, 0x9445},
    {0x0F, 0x9447},
    {0x0F, 0x9449},
    {0x0F, 0x944B},
    {0x0F, 0x944D},
    {0x1E, 0x944F},
    {0x0F, 0x9451},
    {0x0B, 0x9453},
    {0x28, 0x9455},
    {0x13, 0x9457},
    {0x0C, 0x9459},
    {0x00, 0x945D},
    {0x00, 0x945E},
    {0x00, 0x945F},
    {0x00, 0x946D},
    {0x10, 0x946F},
    {0x10, 0x9471},
    {0x40, 0x9473},
    {0x2E, 0x9475},
    {0x10, 0x9477},
    {0x0A, 0x9478},
    {0xE0, 0x947B},
    {0xE0, 0x947C},
    {0xE0, 0x947D},
    {0xE0, 0x947E},
    {0xE0, 0x947F},
    {0xE0, 0x9480},
    {0x14, 0x9483},
    {0x14, 0x9485},
    {0x14, 0x9487},
    {0x35, 0x9501},
    {0x14, 0x9503},
    {0x14, 0x9505},
    {0x31, 0x9507},
    {0x1B, 0x9509},
    {0x15, 0x950B},
    {0x1E, 0x950D},
    {0x1E, 0x950F},
    {0x1E, 0x9511},
    {0x64, 0x9513},
    {0x64, 0x9515},
    {0x64, 0x9517},
    {0x34, 0x951D},
    {0x01, 0x951F},
    {0x01, 0x9521},
    {0x01, 0x9523},
    {0x14, 0x9525},
    {0x14, 0x9527},
    {0x14, 0x9529},
    {0x2F, 0x952B},
    {0x1A, 0x952D},
    {0x14, 0x952F},
    {0x1E, 0x9531},
    {0x1E, 0x9533},
    {0x1E, 0x9535},
    {0x6B, 0x9537},
    {0x7C, 0x9539},
    {0x81, 0x953B},
    {0x0F, 0x9543},
    {0x0F, 0x9545},
    {0x0F, 0x9547},
    {0x0F, 0x9549},
    {0x0F, 0x954B},
    {0x0F, 0x954D},
    {0x15, 0x954F},
    {0x0B, 0x9551},
    {0x08, 0x9553},
    {0x1C, 0x9555},
    {0x0D, 0x9557},
    {0x08, 0x9559},
    {0x00, 0x955D},
    {0x00, 0x955E},
    {0x00, 0x955F},
    {0x00, 0x956D},
    {0x10, 0x956F},
    {0x10, 0x9571},
    {0x40, 0x9573},
    {0x2E, 0x9575},
    {0x10, 0x9577},
    {0x0A, 0x9578},
    {0xE0, 0x957B},
    {0xE0, 0x957C},
    {0xE0, 0x957D},
    {0xE0, 0x957E},
    {0xE0, 0x957F},
    {0xE0, 0x9580},
    {0x14, 0x9583},
    {0x14, 0x9585},
    {0x14, 0x9587},
    {0x00, 0x7F78},
    {0x00, 0x7F89},
    {0x00, 0x7F93},
    {0x1B, 0x924B},
    {0x0A, 0x924C},
    {0x04, 0x9304},
    {0x04, 0x9315},
    {0x50, 0x9250},
    {0x3C, 0x9251},
    {0x14, 0x9252}
};

static const HI_U16 g_au16SensorCfgSeq[][IMX458_MODE_BUTT + 1] = {
    {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x04, 0x0305},
    {0xD8, 0xD8, 0xD8, 0xD6, 0xD8, 0xD8, 0xD8, 0xD6, 0x0307},
    {0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x04, 0x04, 0x030D},
    {0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0x86, 0xD8, 0x030F},
    {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x0310},
    {0x7F, 0x64, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x4648},
    {0x1C, 0x1C, 0x1C, 0x5C, 0x1C, 0x1C, 0x1C, 0x5C, 0x7421},
    {0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0x7423},
    {0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x9104},
    {0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x0342},
    {0xE8, 0x48, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0x0343},
    {0x02, 0x04, 0x09, 0x06, 0x0C, 0x0C, 0x0A, 0x12, 0x0340},
    {0xF0, 0x54, 0x50, 0x41, 0x9C, 0x9C, 0x16, 0xC3, 0x0341},
    {0x00, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0345}, /* B8 */
    {0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x00, 0x0346},
    {0xE0, 0xE0, 0x80, 0x1E, 0xE0, 0x80, 0xE0, 0x00, 0x0347},
    {0x10, 0x0F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0348},
    {0x6F, 0xB9, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x0349}, /* B7 */
    {0x0A, 0x0A, 0x0A, 0x09, 0x0A, 0x0A, 0x0A, 0x0C, 0x034A},
    {0x4F, 0x4F, 0xAF, 0x11, 0x4F, 0xAF, 0x4F, 0x2F, 0x034B},
    {0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0385},
    {0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0387},
    {0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x0C, 0x14, 0x0820},
    {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x90, 0x40, 0x0821},
    {0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0900},
    {0x12, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0901},
    {0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0902},
    {0x01, 0x01, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0401},
    {0x30, 0x20, 0x18, 0x10, 0x10, 0x11, 0x10, 0x10, 0x0405}, /* 1F */
    {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x0408},
    {0xB6, 0x00, 0x42, 0xEA, 0xB8, 0x40, 0xB8, 0x68, 0x0409}, /* 3A */
    {0x00, 0x00, 0x20, 0x00, 0x00, 0x1C, 0x00, 0x3C, 0x040B},
    {0x0F, 0x0F, 0x0F, 0x0A, 0x0F, 0x0F, 0x0F, 0x0F, 0x040C}, /* 0E */
    {0x02, 0x02, 0xEC, 0x9C, 0x00, 0xF0, 0x00, 0xA0, 0x040D}, /* 8A */
    {0x02, 0x04, 0x08, 0x05, 0x08, 0x08, 0x08, 0x0B, 0x040E},
    {0xD0, 0x38, 0xF0, 0xF4, 0x70, 0xF8, 0x70, 0xB8, 0x040F},
    {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x300D},
    {0x05, 0x07, 0x0A, 0x0A, 0x0F, 0x0F, 0x0F, 0x0F, 0x034C},
    {0x00, 0x80, 0x9C, 0x9C, 0x00, 0x00, 0x00, 0xA0, 0x034D},
    {0x02, 0x04, 0x05, 0x05, 0x08, 0x08, 0x08, 0x0B, 0x034E},
    {0xD0, 0x38, 0xF4, 0xF4, 0x70, 0x70, 0x70, 0xB8, 0x034F},
    {0x02, 0x04, 0x09, 0x06, 0x0C, 0x0C, 0x0A, 0x12, 0x0202},
    {0xE6, 0x4A, 0x46, 0x37, 0x92, 0x92, 0x0C, 0xB9, 0x0203},
    {0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x5C, 0x1C, 0x7421},
    {0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7BCD},
    {0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x9010},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x9104},
    {0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x9419},
    {0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x941B},
    {0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x9519},
    {0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x951B},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3030},
    {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x407C},
    {0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x407D},
    {0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x407F},
    {0x09, 0x03, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x5B29},
    {0x19, 0x09, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x5B2F}
};

void imx458_init(VI_PIPE vi_pipe)
{
    HI_U32  i, u32SeqEntries;
    HI_U8   u8ImgMode;
    HI_BOOL bInit;
    HI_S32  ret = HI_SUCCESS;
    HI_U16  u16RegAddr, u16RegData;
    ISP_SNS_STATE_S *pastimx458 = HI_NULL;
    const IMX458_VIDEO_MODE_TBL_S *imx458modetb1 = HI_NULL;
    pastimx458 = imx458_get_ctx(vi_pipe);
    bInit      = pastimx458->bInit;
    u8ImgMode  = pastimx458->u8ImgMode;
    imx458modetb1 = imx458_get_mode_tb1(u8ImgMode);
    if (bInit == HI_FALSE) {
        imx458_i2c_init(vi_pipe); /* 2. sensor i2c init */
    }
    if (!g_bStandby[vi_pipe] || !pastimx458->bInit) {
        u32SeqEntries = sizeof(g_au16SensorCfgSeqComm) / sizeof(g_au16SensorCfgSeqComm[0]);
        for (i = 0; i < u32SeqEntries; i++) {
            u16RegAddr = g_au16SensorCfgSeqComm[i][1];
            u16RegData = g_au16SensorCfgSeqComm[i][0];
            if (u16RegData == NA) {
                continue;
            }
            imx458_write_register(vi_pipe, u16RegAddr, u16RegData);
        }
    }
    u32SeqEntries = sizeof(g_au16SensorCfgSeq) / sizeof(g_au16SensorCfgSeq[0]);
    for (i = 0; i < u32SeqEntries; i++) {
        u16RegAddr = g_au16SensorCfgSeq[i][IMX458_MODE_BUTT];
        u16RegData = g_au16SensorCfgSeq[i][u8ImgMode];
        if (u16RegData == NA) {
            continue;
        }
        ret += imx458_write_register(vi_pipe, u16RegAddr, u16RegData);
    }
    for (i = 0; i < pastimx458->astRegsInfo[0].u32RegNum; i++) {
        ret += imx458_write_register(vi_pipe,
                                     pastimx458->astRegsInfo[0].astI2cData[i].u32RegAddr,
                                     pastimx458->astRegsInfo[0].astI2cData[i].u32Data);
    }
    if (ret != HI_SUCCESS) {
        SNS_ERR_TRACE("write register failed!\n");
        return;
    }
    pastimx458->bInit = HI_TRUE;
    imx458_restart(vi_pipe);
    printf("IMX458 %s init succuss!\n", imx458modetb1->pszModeName);
    return;
}

void imx458_exit(VI_PIPE vi_pipe)
{
    HI_S32 ret;
    ret = imx458_i2c_exit(vi_pipe);
    if (ret != HI_SUCCESS) {
        SNS_ERR_TRACE("i2c exit failed!\n");
        return;
    }
    g_bStandby[vi_pipe] = HI_FALSE;
    return;
}
